﻿#include "GlesContext.h"
#include "Render/Shapes.h"
#include "Render/Primitive.h"
#include <string>
#include <GLES3/gl3.h>

#define STR(x) #x

const char* vertex_shader = STR(

#version 300 es \n

in vec4 a_position;
in vec2 a_texCoord;
in mat4 a_matrix;
out vec2 v_texCoord;

void main() {
	v_texCoord = a_texCoord;
	gl_Position = a_matrix * a_position;
}
);

const char* fragment_shader_yuv = STR(

#version 300 es \n

precision mediump float;
in vec2 v_texCoord;

uniform sampler2D SamplerY;
uniform sampler2D SamplerU;
uniform sampler2D SamplerV;

out vec4 outColor;

mat3 colorConversionMatrix = mat3(
	1.0, 1.0, 1.0,
	0.0, -0.39465, 2.03211,
	1.13983, -0.58060, 0.0);

vec3 yuv_rgb(vec2 pos)
{
	vec3 yuv;
	yuv.x = texture(SamplerY, pos).r;
	yuv.y = texture(SamplerU, pos).r - 0.5;
	yuv.z = texture(SamplerV, pos).r - 0.5;
	return colorConversionMatrix * yuv;
}

void main()
{
	outColor = vec4(yuv_rgb(v_texCoord), 1.0);
}
);

const char* fragment_shader_yuy2 = STR(

#version 300 es \n

precision mediump float;
in vec2 v_texCoord;

uniform sampler2D SamplerY;
uniform sampler2D SamplerU;
uniform sampler2D SamplerV;

out vec4 outColor;

mat3 colorConversionMatrix = mat3(
	1.0, 1.0, 1.0,
	0.0, -0.39465, 2.03211,
	1.13983, -0.58060, 0.0);

vec3 yuv_rgb(vec2 pos)
{
	vec3 yuv;
	yuv.x = texture(SamplerY, pos).r;
	yuv.y = texture(SamplerU, pos).g - 0.5;
	yuv.z = texture(SamplerV, pos).a - 0.5;
	return colorConversionMatrix * yuv;
}

void main()
{
	outColor = vec4(yuv_rgb(v_texCoord), 1.0);
}
);

const char* fragment_shader_rgb = STR(

#version 300 es \n

precision mediump float;
in vec2 v_texCoord;

uniform sampler2D SamplerY;

out vec4 outColor;

void main()
{
	outColor = vec4(texture(SamplerY, v_texCoord).bgra);
}
);

GlesContext::GlesContext() 
	: _primitive(nullptr)
	, _width(0)
	, _height(0)
	, _type(ImageType::Unknown)
{
	// 设置使用的清屏颜色
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	
	// 逆时针为正面
	glFrontFace(GL_CCW);

	// 剔除操作
	glDisable(GL_CULL_FACE);
	glCullFace(GL_BACK);

	// 模板测试
	glDisable(GL_STENCIL_TEST);

	// 深度测试
	glDisable(GL_DEPTH_TEST);

	// 深度缓冲区
	glDepthMask(GL_FALSE);

	// 混合
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

GlesContext::~GlesContext()
{
	if (_primitive)
	{
		delete _primitive;
		_primitive = nullptr;
	}
}

void GlesContext::setup(ImageType type)
{
	if (type == _type)
	{
		return;
	}

	_type = type;

	if (_primitive)
	{
		delete _primitive;
		_primitive = nullptr;
	}

	_primitive = new Primitive();

	GLProgram* program = nullptr;

	switch (type)
	{
	case ImageType::YUYV422:
		program = GLProgram::create(vertex_shader, fragment_shader_yuy2);
		break;
	case ImageType::YUV422:
	case ImageType::YUV420:
		program = GLProgram::create(vertex_shader, fragment_shader_yuv);
		break;
	case ImageType::RGB:
	case ImageType::RGBA:
		program = GLProgram::create(vertex_shader, fragment_shader_rgb);
		break;
	default:
		program = GLProgram::create(vertex_shader, fragment_shader_yuv);
		break;
	}

	_primitive->setProgram(std::shared_ptr<GLProgram>(program));

	// 生成图形数据
	float* vertices;		// 位置数据(数组)
	unsigned int* indices;	// 位置索引(数组)
	float* textureCoords;	// 纹理坐标(数组)

	int size = 2;
	int indicesCount = esGenSquareGrid(size, &vertices, &textureCoords, &indices);
	int vertexCount = size * size;

	VertexData* vertexData = VertexData::create();
	_primitive->setVertexData(std::shared_ptr<VertexData>(vertexData));

	// 顶点
	int posSize = 3;
	VertexBuffer* vertexBuffer = VertexBuffer::create(sizeof(float) * posSize, vertexCount);
	vertexBuffer->updateVertices(vertices, vertexCount, 0);

	VertexStreamAttribute stream(0, program->getAttribLocation("a_position"), GL_FLOAT, posSize);
	vertexData->setStream(std::shared_ptr<VertexBuffer>(vertexBuffer), stream);

	// 纹理索引
	int coordSize = 3;
	VertexBuffer* coordBuffer = VertexBuffer::create(sizeof(float) * coordSize, vertexCount);
	coordBuffer->updateVertices(textureCoords, vertexCount, 0);

	VertexStreamAttribute coordStream(0, program->getAttribLocation("a_texCoord"), GL_FLOAT, coordSize);
	vertexData->setStream(std::shared_ptr<VertexBuffer>(coordBuffer), coordStream);

	// 索引
	IndexBuffer* indexBugger = IndexBuffer::create(sizeof(unsigned int), indicesCount);
	indexBugger->updateIndices(indices, indicesCount, 0);
	_primitive->setIndexBuffer(std::shared_ptr<IndexBuffer>(indexBugger));

	// 变换矩阵
	MatrixBuffer* matrixBuffer = MatrixBuffer::create(program->getAttribLocation("a_matrix"));
	_primitive->setMatrixBuffer(std::shared_ptr<MatrixBuffer>(matrixBuffer));

	// 纹理(图片)
	TextureData* textureData = TextureData::create();
	_primitive->setTextureData(std::shared_ptr<TextureData>(textureData));

	TextureBuffer* textureBufferY = TextureBuffer::create(program->getUniformLocation("SamplerY"));
	textureData->setStream(std::shared_ptr<TextureBuffer>(textureBufferY), 0);

	TextureBuffer* textureBufferU = TextureBuffer::create(program->getUniformLocation("SamplerU"));
	textureData->setStream(std::shared_ptr<TextureBuffer>(textureBufferU), 1);

	TextureBuffer* textureBufferV = TextureBuffer::create(program->getUniformLocation("SamplerV"));
	textureData->setStream(std::shared_ptr<TextureBuffer>(textureBufferV), 2);

	_primitive->reload();

	free(vertices);
	free(indices);
	free(textureCoords);
}

void GlesContext::draw(int width ,int height)
{
	if (_width != width || _height != height)
	{
		_width = width;
		_height = height;

		_matrix.setViewSize(width, height);
		glViewport(0, 0, width, height);
	}

	// 清空颜色缓冲区
	glClear(GL_COLOR_BUFFER_BIT);

	if (_matrix.isChange())
	{
		_primitive->matrixBuffer()->updateMatrix(&_matrix.getMatrix());
	}
	
	// 切换opengl纹理状态机并渲染
	_primitive->textureData()->use();
	_primitive->draw();
}

void GlesContext::updateImage(void* buffer[], int width, int height)
{
	// YUY2  是 4:2:2  [Y0 U0 Y1 V0]
	auto& textureData = _primitive->textureData();

	switch (_type)
	{
	case ImageType::YUYV422:
		// 2个分量取一次y,取分量第1个元素
		textureData->getStream(0)->updateTexture(buffer[0], width, height, GL_LUMINANCE_ALPHA);

		// 4个分量取一次u,取分量第2个元素
		textureData->getStream(1)->updateTexture(buffer[1], width / 2, height, GL_RGBA);

		// 4个分量取一次v,取分量第4个元素
		textureData->getStream(2)->updateTexture(buffer[2], width / 2, height, GL_RGBA);
		break;
	case ImageType::YUV422:
		// 1个分量取一次y,取分量第1个元素
		textureData->getStream(0)->updateTexture(buffer[0], width, height, GL_LUMINANCE);

		// 1个分量取一次u,取分量第1个元素
		textureData->getStream(1)->updateTexture(buffer[1], width / 2, height, GL_LUMINANCE);

		// 1个分量取一次v,取分量第1个元素
		textureData->getStream(2)->updateTexture(buffer[2], width / 2, height, GL_LUMINANCE);
		break;
	case ImageType::YUV420:
		// 1个分量取一次y,取分量第1个元素
		textureData->getStream(0)->updateTexture(buffer[0], width, height, GL_LUMINANCE);

		// 1个分量取一次u,取分量第1个元素
		textureData->getStream(1)->updateTexture(buffer[1], width / 2, height / 2, GL_LUMINANCE);

		// 1个分量取一次v,取分量第1个元素
		textureData->getStream(2)->updateTexture(buffer[2], width / 2, height / 2, GL_LUMINANCE);
		break;
	case ImageType::RGB:
		textureData->getStream(0)->updateTexture(buffer[0], width, height, GL_RGB);
		break;
	case ImageType::RGBA:
		textureData->getStream(0)->updateTexture(buffer[0], width, height, GL_RGBA);
		break;
	default:
		break;
	}
}

bool GlesContext::isValid()
{
	return _type != ImageType::Unknown;
}
